package de.mrapp.ohos_util.view;

import de.mrapp.util.Condition;
import de.mrapp.ohos_util.logging.LogUtil;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.LayoutScatter;
import ohos.app.Context;
import ohos.utils.Pair;

import java.util.Map;

public class ViewRecycler<ItemType, ParamType> extends AbstractViewRecycler<ItemType, ParamType> {
    /**
     * Creates a new recycler, which allows to cache views in order to be able to reuse them later,
     * instead of inflating new instances.
     *
     * @param inflater The layout inflater, which should be used to inflate views, as an instance of the
     *                 class {@link LayoutScatter}. The layout inflater may not be null
     * @param context
     */
    public ViewRecycler(LayoutScatter inflater, Context context) {
        super(inflater, context);
    }

    public final Pair<Component, Boolean> inflate(final ItemType item,
                                                  final ComponentContainer parent,
                                                  final ParamType... params) {
        return inflate(item, parent, true, params);
    }

    public final Pair<Component, Boolean> inflate(final ItemType item,
                                                  final ComponentContainer parent,
                                                  final boolean useCache,
                                                  final ParamType... params) {
        Condition.INSTANCE.ensureNotNull(params, "The array may not be null");
        Condition.INSTANCE.ensureNotNull(getAdapter(), "No adapter has been set",
                IllegalStateException.class);
        LogUtil.loge("=== inflate ViewRecycler");
        Component view = getView(item);
        boolean inflated = false;

        if (view == null) {
            int viewType = getAdapter().getViewType(item);

            if (useCache) {
                view = pollUnusedView(viewType);
            }

            if (view == null) {
                view = getAdapter()
                        .onInflateView(getLayoutScatter(), parent, item, viewType, params);
                inflated = true;
                getLogger().logInfo(getClass(),
                        "Inflated view to visualize item " + item + " using view type " + viewType);
            } else {
                getLogger().logInfo(getClass(),
                        "Reusing view to visualize item " + item + " using view type " + viewType);
            }

            getActiveViews().put(item, view);
        }

        getAdapter().onShowView(getContext(), view, item, inflated, params);
        getLogger().logDebug(getClass(), "Updated view of item " + item);
        return Pair.create(view, inflated);
    }

    @Override
    public Pair<Component, Boolean> inflate(ItemType item, boolean useCache, ParamType... params) {
        return inflate(item, null, useCache, params);
    }

    @Override
    public void remove(ItemType item) {
        Condition.INSTANCE.ensureNotNull(item, "The item may not be null");
        Condition.INSTANCE.ensureNotNull(getAdapter(), "No adapter has been set",
                IllegalStateException.class);
        Component component = getActiveViews().remove(item);

        if (component != null) {
            getAdapter().onRemoveView(component, item);
            int viewType = getAdapter().getViewType(item);
            addUnusedView(component, viewType);
            getLogger().logInfo(getClass(), "Removed view of item " + item);
        } else {
            getLogger().logDebug(getClass(),
                    "Did not remove view of item " + item + ". View is not inflated");
        }
    }

    @Override
    public void removeAll() {
        Condition.INSTANCE.ensureNotNull(getAdapter(), "No adapter has been set",
                IllegalStateException.class);

        for (Map.Entry<ItemType, Component> entry : getActiveViews().entrySet()) {
            ItemType item = entry.getKey();
            Component component = entry.getValue();
            getAdapter().onRemoveView(component, item);
            int viewType = getAdapter().getViewType(item);
            addUnusedView(component, viewType);
        }

        getActiveViews().clear();
        getLogger().logInfo(getClass(), "Removed all views");
    }
}
